#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <string>
#include <cstring>
#include <unistd.h>
//套接字接口
namespace SocketInter
{
#define SIZE 1024
    static const std::string defaultip = "0.0.0.0";
    static const int DEFAULT_NUM = 10;
    enum
    {
        SocketErr = 1,
        BindErr,
        ListenErr,
        AcceptErr,
        ConnectErr
    };
    class SockIn
    {
    public:
        SockIn(const uint16_t &port, const std::string &ip = defaultip)
            : _port(port), _ip(ip)
        {}
        void InitSockaddr()
        {
            memset(&_local, 0, sizeof(_local));
            memset(&_client, 0, sizeof(_client));

            _local.sin_family = AF_INET;
            _local.sin_port = htons(_port);
            _local.sin_addr.s_addr = inet_addr(_ip.c_str());
            
            _len = sizeof(_local);
            _c_len = sizeof(_client);
        }

        int Socket()
        {
            _listenfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listenfd < 0)
            {
                std::cout << "socket errno" <<std::endl;
                exit(SocketErr);
            }
            
            return _listenfd;
        }

        void Bind()
        {

            if (bind(_listenfd, (const sockaddr *)(&_local), _len) < 0)
            {
                exit(BindErr);   
            }
        }

        void Listen()
        {
            if (listen(_listenfd, DEFAULT_NUM) < 0)
            {
                exit(ListenErr);
            }
            
        }

        int Accept()
        {
            
            int sockfd = accept(_listenfd, (sockaddr *)(&_client), &_c_len);
            if (sockfd < 0)
            {
                exit(AcceptErr);
            }

            char ip[SIZE];
            inet_ntop(AF_INET,&_client.sin_addr,ip,sizeof(ip));
            _c_ip = ip;
            _port = ntohs(_client.sin_port);
            return sockfd;
        }

        void Connect()
        {
            if (connect(_listenfd, (const sockaddr *)(&_local), _len) < 0)
            {
                std::cout << "连接失败" <<std::endl;
                exit(ConnectErr);
            }
        }

        void CloseListenfd()
        {
            close(_listenfd);
        }
        const std::string GetClientip()
        {
            return _c_ip;
        }

        const uint16_t GetClientport()
        {
            return _c_port;
        }
        const uint16_t listenfd()
        {
            return _listenfd;
        }
    private:
        uint16_t _port;
        std::string _ip;
        int _listenfd;

        sockaddr_in _local;
        sockaddr_in _client;

        uint16_t _c_port;
        std::string _c_ip;

        socklen_t _len;
        socklen_t _c_len;
    };
}